#include <page_manager.h>
#include <disp_manager.h>
#include <input_manager.h>
#include <video_manager.h>
#include <convert_manager.h>
#include <render.h>

#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include <unistd.h>

static unsigned char status = 0;
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;


void *VideoEventHandler(void *data){
    PInputEvent ptInputEvent = (PInputEvent) data;
    if (ptInputEvent->iType == INPUT_TYPE_BUTTON){
        // 按下 按键2 触发关闭摄像头
        if (ptInputEvent->iCode == 0 && ptInputEvent->iValue == 2){
            pthread_mutex_lock(&g_tMutex);
            status = 0;
            pthread_mutex_unlock(&g_tMutex);
        }
        else if (ptInputEvent->iValue == 3 && ptInputEvent->iCode == 1){
            printf("\n\n 按下结束按钮 \n");
            GetDefaultDispDev()->CleanScreen(0);
            exit(0);
        }
    }
    return NULL;
}

static void VideoPageRun(void *pParams)
{
    int iError;
    T_VideoDevice tVideoDevice;
    PT_VideoConvert ptVideoConvert;
    int iPixelFormatOfVideo;
    int iPixelFormatOfDisp;

    PT_VideoBuf ptVideoBufCur;
    T_VideoBuf tVideoBuf;
    T_VideoBuf tConvertBuf;
    T_VideoBuf tZoomBuf;
    T_VideoBuf tFrameBuf;
    
    int iLcdWidth;
    int iLcdHeigt;
    int iLcdBpp;

    int iTopLeftX;
    int iTopLeftY;

    char *strVideoDeviceName;

    float k;
    
    strVideoDeviceName = GetVideoDeviceName();

    iError = VideoDeviceInit(strVideoDeviceName, &tVideoDevice);
    if (iError)
    {
        DBG_PRINTF("VideoDeviceInit for %s error!\n", strVideoDeviceName);
        return ;
    }

    GetDispResolution(&iLcdWidth, &iLcdHeigt, &iLcdBpp);
    GetVideoBufForDisplay(&tFrameBuf);
    iPixelFormatOfDisp = tFrameBuf.iPixelFormat;

    tVideoDevice = *(GetVideoDevice());
    iPixelFormatOfVideo = tVideoDevice.ptOPr->GetFormat(&tVideoDevice);

    ptVideoConvert = GetVideoConvertForFormats(iPixelFormatOfVideo, iPixelFormatOfDisp);
    if (NULL == ptVideoConvert)
    {
        DBG_PRINTF("can not support this format convert\n");
        return ;
    }

    /* 启动摄像头设备 */
    iError = tVideoDevice.ptOPr->StartDevice(&tVideoDevice);
    if (iError)
    {
        DBG_PRINTF("StartDevice for %s error!\n", strVideoDeviceName);
        return ;
    }

    /* 注册响应函数 */
	T_EventHandler handler;
	handler.name = "video";
	handler.HandleFunc = VideoEventHandler;
	EventHandlerRegister(&handler);

    memset(&tVideoBuf, 0, sizeof(tVideoBuf));
    memset(&tConvertBuf, 0, sizeof(tConvertBuf));
    tConvertBuf.iPixelFormat     = iPixelFormatOfDisp;
    tConvertBuf.tPixelDatas.iBpp = iLcdBpp;
    
    memset(&tZoomBuf, 0, sizeof(tZoomBuf));

	pthread_mutex_lock(&g_tMutex);
	status = 1;
    pthread_mutex_unlock(&g_tMutex);
	while (status)
	{
        /* 读入摄像头数据 */
        iError = tVideoDevice.ptOPr->GetFrame(&tVideoDevice, &tVideoBuf);
        if (iError)
        {
            DBG_PRINTF("GetFrame for %s error!\n", strVideoDeviceName);
            return ;
        }
        ptVideoBufCur = &tVideoBuf;

        if (iPixelFormatOfVideo != iPixelFormatOfDisp)
        {
            /* 转换为RGB */
            iError = ptVideoConvert->Convert(&tVideoBuf, &tConvertBuf);
            // DBG_PRINTF("Convert %s, ret = %d\n", ptVideoConvert->name, iError);
            if (iError)
            {
                DBG_PRINTF("Convert for %s error!\n", strVideoDeviceName);
                return ;
            }            
            ptVideoBufCur = &tConvertBuf;
        }
        

        /* 如果图像分辨率大于LCD, 缩放 */
        if (ptVideoBufCur->tPixelDatas.iWidth > iLcdWidth || ptVideoBufCur->tPixelDatas.iHeight > iLcdHeigt)
        {
            /* 确定缩放后的分辨率 */
            /* 把图片按比例缩放到VideoMem上, 居中显示
             * 1. 先算出缩放后的大小
             */
            k = (float)ptVideoBufCur->tPixelDatas.iHeight / ptVideoBufCur->tPixelDatas.iWidth;
            tZoomBuf.tPixelDatas.iWidth  = iLcdWidth;
            tZoomBuf.tPixelDatas.iHeight = iLcdWidth * k;
            if ( tZoomBuf.tPixelDatas.iHeight > iLcdHeigt)
            {
                tZoomBuf.tPixelDatas.iWidth  = iLcdHeigt / k;
                tZoomBuf.tPixelDatas.iHeight = iLcdHeigt;
            }
            tZoomBuf.tPixelDatas.iBpp        = iLcdBpp;
            tZoomBuf.tPixelDatas.iLineBytes  = tZoomBuf.tPixelDatas.iWidth * tZoomBuf.tPixelDatas.iBpp / 8;
            tZoomBuf.tPixelDatas.iTotalBytes = tZoomBuf.tPixelDatas.iLineBytes * tZoomBuf.tPixelDatas.iHeight;

            if (!tZoomBuf.tPixelDatas.aucPixelDatas)
            {
                tZoomBuf.tPixelDatas.aucPixelDatas = malloc(tZoomBuf.tPixelDatas.iTotalBytes);
            }
            
            PicZoom(&ptVideoBufCur->tPixelDatas, &tZoomBuf.tPixelDatas);
            ptVideoBufCur = &tZoomBuf;
        }

        /* 合并进framebuffer */
        /* 接着算出居中显示时左上角坐标 */
        iTopLeftX = (iLcdWidth - ptVideoBufCur->tPixelDatas.iWidth) / 2;
        iTopLeftY = (iLcdHeigt - ptVideoBufCur->tPixelDatas.iHeight) / 2;

        PicMerge(iTopLeftX, iTopLeftY, &ptVideoBufCur->tPixelDatas, &tFrameBuf.tPixelDatas);

        FlushPixelDatasToDev(&tFrameBuf.tPixelDatas);

        iError = tVideoDevice.ptOPr->PutFrame(&tVideoDevice, &tVideoBuf);
        if (iError)
        {
            DBG_PRINTF("PutFrame for %s error!\n", strVideoDeviceName);
            return ;
        }                    

        /* 把framebuffer的数据刷到LCD上, 显示 */

	}
    // 返回上一级界面
    RunPage(NULL);
}

static void VideoPageExit(void *pParams){
	/* 退出页面逻辑 */
	pthread_mutex_lock(&g_tMutex);
	status = 0;
    pthread_mutex_unlock(&g_tMutex);
    
    PT_VideoDevice ptVideoDevice;
    ptVideoDevice = GetVideoDevice();
    ptVideoDevice->ptOPr->StopDevice(ptVideoDevice);
    ptVideoDevice->ptOPr->ExitDevice(ptVideoDevice);

	/* 清屏 */
	PT_DispOpr ptDispOpr;
	ptDispOpr = GetDefaultDispDev();
	ptDispOpr->CleanScreen(0);
}

static T_PageAction g_tVideoPage = {
	.name = "video",
	.Run  = VideoPageRun,
	.Exit = VideoPageExit,
};

void VideoPageRegister(void)
{
	PageRegister(&g_tVideoPage);
}